#include <stdio.h>
#include "max30102.h"



#define 	TAG                   "MAX30102"



/**
 * @brief init the gpio intr for MAX30102
 */
static esp_err_t max30102_gpio_intr_init(void)
{
    gpio_config_t io_conf = {};
    io_conf.intr_type = GPIO_INTR_DISABLE;
    io_conf.mode = GPIO_MODE_INPUT;
    io_conf.pin_bit_mask = (1ULL<<MAX30102_GPIO_INT);
    io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
    io_conf.pull_up_en = GPIO_PULLUP_DISABLE;
    ESP_ERROR_CHECK(gpio_config(&io_conf));
    
    return ESP_OK;
}  
/**
*  ???
*/ 
esp_err_t max30102_register_write_byte(uint8_t reg_addr, uint8_t data)
{
    uint8_t write_buf[2] = {reg_addr, data};

    return i2c_master_write_to_device(MAX30102_I2C_NUM,reg_addr,write_buf,sizeof(write_buf),MAX30102_I2C_TIMEOUT_MS / portTICK_PERIOD_MS);
}
/**
 *   ???
*/ 
esp_err_t max30102_register_read(uint8_t reg_addr, uint8_t *data, size_t len)
{
    return i2c_master_write_read_device(MAX30102_I2C_NUM,MAX30102_Device_address,&reg_addr, 1, data, len,MAX30102_I2C_TIMEOUT_MS / portTICK_PERIOD_MS);
}

/**
 *   i2c?gpio?????????
*/ 
void max30102_init(void)
{
    ESP_ERROR_CHECK(max30102_i2c_init());
    ESP_LOGI(TAG, "MAX30102 I2C initialized successfully");
    max30102_gpio_intr_init();
    ESP_LOGI(TAG, "MAX30102 GPIO INTR initialized successfully");

    // reset
    ESP_ERROR_CHECK(max30102_register_write_byte(REG_MODE_CONFIG, 0x40)); 
    vTaskDelay(100 / portTICK_PERIOD_MS);   

    // Interrupt Enable
    ESP_ERROR_CHECK(max30102_register_write_byte(REG_INTR_ENABLE_1, 0xc0)); // enable interrupts: A_FULL: FIFO Almost Full Flag and PPG_RDY: New FIFO Data Ready
    ESP_ERROR_CHECK(max30102_register_write_byte(REG_INTR_ENABLE_2, 0x02)); // enable interrupt: DIE_TEMP_RDY: Internal Temperature Ready Flag 

    // FIFO
    ESP_ERROR_CHECK(max30102_register_write_byte(REG_FIFO_WR_PTR, 0x00)); // clear FIFO Write Pointer
    ESP_ERROR_CHECK(max30102_register_write_byte(REG_OVF_COUNTER, 0x00)); // clear FIFO Overflow Counter
    ESP_ERROR_CHECK(max30102_register_write_byte(REG_FIFO_RD_PTR, 0x00)); // clear FIFO Read Pointer 

    // FIFO Configuration
    ESP_ERROR_CHECK(max30102_register_write_byte(REG_FIFO_CONFIG, 0x0f)); // SMP_AVE = 0b000: 1 averaging, FIFO_ROLLOVER_EN = 0, FIFO_A_FULL = 0xf 

    // Mode Configuration 
    ESP_ERROR_CHECK(max30102_register_write_byte(REG_MODE_CONFIG, 0x03)); // MODE = 0b011: SpO2 mode

    // SpO2 Configuration 
    ESP_ERROR_CHECK(max30102_register_write_byte(REG_SPO2_CONFIG, 0x47)); // SPO2_ADC_RGE = 0b10: 8192, SPO2_SR = 0b001: 100 SAMPLES PER SECOND, 
                                                               // LED_PW = 0b11: PULSE WIDTH 411, ADC RESOLUTION 18

    // LED Pulse Amplitude
    ESP_ERROR_CHECK(max30102_register_write_byte(REG_LED1_PA, 0x50)); // LED1_PA(red) = 0x24, LED CURRENT 16mA 
    ESP_ERROR_CHECK(max30102_register_write_byte(REG_LED2_PA, 0x50)); // LED2_PA(IR) = 0x24, LED CURRENT 16mA 
    // ESP_ERROR_CHECK(max30102_register_write_byte(0x10, 0x50)); // PILOT_PA = 0x24, LED CURRENT 16mA


    // clear PPG_RDY ! Cannot receive the first interrupt without clearing !  
    uint8_t data;
    ESP_ERROR_CHECK(max30102_register_read(REG_INTR_STATUS_1, &data, 1));
    ESP_LOGI(TAG, "Interrupt Status 1: 0x%x", data);
    ESP_ERROR_CHECK(max30102_register_read(REG_INTR_STATUS_2, &data, 1));
    ESP_LOGI(TAG, "Interrupt Status 2: 0x%x", data);
}

esp_err_t max30102_read_fifo(uint16_t *fifo_red, uint16_t *fifo_ir)
{
	uint16_t un_temp;
	uint16_t fifo_temp_red = 0;
	uint16_t fifo_temp_ir = 0;
	uint8_t status_1, status_2;
	uint8_t ach_i2c_data[6];
	esp_err_t ret = ESP_OK;
	ret = max30102_register_read(REG_INTR_STATUS_1, &status_1, 1);
	if (ret != ESP_OK) 
		return ret;

	ret = max30102_register_read(REG_INTR_STATUS_2, &status_2, 1);
	if (ret != ESP_OK) 
		return ret;

	ret = max30102_register_read(REG_FIFO_DATA, ach_i2c_data, 6);
	if (ret != ESP_OK) 
		return ret;
	// rea data
	un_temp = ach_i2c_data[0];
	un_temp <<= 14;
	fifo_temp_red += un_temp;

	un_temp = ach_i2c_data[1];
	un_temp <<= 6;
	fifo_temp_red += un_temp;

	un_temp = ach_i2c_data[2];
	un_temp >>= 2;
	fifo_temp_red += un_temp;

	// ir data
	un_temp = ach_i2c_data[3];
	un_temp <<= 14;
	fifo_temp_ir += un_temp;

	un_temp = ach_i2c_data[4];
	un_temp <<= 6;
	fifo_temp_ir += un_temp;

	un_temp = ach_i2c_data[5];
	un_temp >>= 2;
	fifo_temp_ir += un_temp;

	if (fifo_temp_ir <= 10000) {
		fifo_temp_ir = 0;
	}
	if (fifo_temp_red <= 10000) {
		fifo_temp_red = 0;
	}
	*fifo_red = fifo_temp_red;
	*fifo_ir = fifo_temp_ir;

	return ret;
}

esp_err_t max30102_read_temp(float *temperature)
{
	uint8_t temp_Integer, temp_Frac;
	float temp;
	uint8_t status_1, status_2;
	esp_err_t ret = ESP_OK;

	if (gpio_get_level(MAX30102_GPIO_INT) != 0) 
    {
		ESP_LOGI(TAG, "ESP_ERR_INVALID_STATE max30102.c(line 154)");
		return ESP_ERR_INVALID_STATE; // ??????
	}

	ret = max30102_register_read(REG_INTR_STATUS_1, &status_1, 1);
	if (ret != ESP_OK) 
		return ret;
	ret = max30102_register_read(REG_INTR_STATUS_2, &status_2, 1);
	if (ret != ESP_OK) 
		return ret;
	ret = max30102_register_read(REG_TEMP_INTR, &temp_Integer, 1);
	if (ret != ESP_OK) 
		return ret;
	ret = max30102_register_read(REG_TEMP_FRAC, &temp_Frac, 1);
	if (ret != ESP_OK) 
		return ret;

	temp = temp_Integer + (float)temp_Frac * 0.0625;
	*temperature = temp;
	return ret;
}
